package org.datascooter.bundle.attribute;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Logger;

import org.datascooter.utils.LangUtils;

/**
 * Purpose for define entities contained into other entities in runtime. Store with special cross table for handle links between entities as distinct from PersistableChildBundle purposed for the same
 * operations but with particular link method through foreign keys
 * 
 * @author nemo
 * 
 */
public class MethodContainerAttribute extends ContainerAttribute {

	private Method getter;
	private Method setter;

	/**
	 * Purposed for a mapping of a contained entities Parameter entity - may be String or Class
	 */
	public MethodContainerAttribute(String name, String entity, String mapKeyAttribute, PersistencePolicy policy, boolean embedded, boolean fetchLazy) {
		super(name);
		this.entity = entity;
		this.mapKeyAttribute = mapKeyAttribute;
		this.policy = (policy == null ? PersistencePolicy.ALL : policy);
		this.embedded = embedded;
		this.fetchLazy = fetchLazy;
	}

	@Override
	public void explore(Class<?> clazz) {
		if (clazz != null) {
			try {
				if (name.startsWith(GET)) {
					getter = clazz.getMethod(name);
				} else {
					getter = clazz.getMethod(GET + LangUtils.capitalize(name));
				}
				setGetClass(getter.getReturnType());
			} catch (Exception e) {
				Logger.getLogger(this.getClass().getName()).severe("*** Add Container Attribute -  provide getter:" + e.getMessage());
				setPolicy(PersistencePolicy.INSERT);
			}
			try {
				if (name.startsWith(SET)) {
					setter = clazz.getMethod(name, new Class[] {
						getClass
					});
				} else {
					setter = clazz.getMethod(SET + LangUtils.capitalize(name), new Class[] {
						getClass
					});
				}
			} catch (Exception e) {
				Logger.getLogger(this.getClass().getName()).severe("*** Add Container Attribute -  provide setter:" + e.getMessage());
				setPolicy(PersistencePolicy.SELECT);
			}
			returnType = getter.getReturnType();
			setGetClass(returnType);
			setSetClass(returnType);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public ContainerAttribute copy() {
		return new MethodContainerAttribute(name, entity, mapKeyAttribute, getPolicy(), embedded, fetchLazy);
	}

	@SuppressWarnings("unchecked")
	public <T> T getValue(Object obj) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		return (T) getter.invoke(obj);
	}

	@Override
	public void setValue(Object obj, Object param) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		setter.invoke(obj, param);
	}
}
